package cn.ilikes.tools.nosql.jpa.query.iquerys;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.Parameter;

import org.apache.hadoop.hbase.client.Result;
import org.slf4j.Logger;

import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory.Default;

import cn.ilikes.tools.logs.Loggerfactory;
import cn.ilikes.tools.nosql.jpa.clients.AbClient;
import cn.ilikes.tools.nosql.jpa.clients.JPASQLClientsException;
import cn.ilikes.tools.nosql.jpa.clients.handers.DataHander;
import cn.ilikes.tools.nosql.jpa.clients.handers.JPASQLDataHnaderException;
import cn.ilikes.tools.nosql.jpa.clients.indexs.ABClientIndex;
import cn.ilikes.tools.nosql.jpa.clients.indexs.ClientIndexingException;
import cn.ilikes.tools.nosql.jpa.graphs.Node;
import cn.ilikes.tools.nosql.jpa.metadatas.EntityMetaData;
import cn.ilikes.tools.nosql.jpa.persistences.contexts.AbstractContext;
import cn.ilikes.tools.nosql.jpa.query.JPASQLQueryRunTimeException;
import cn.ilikes.tools.nosql.jpa.query.iquerys.IQuery.QueryType;
import cn.ilikes.tools.nosql.jpa.query.pages.PageEntitys;
import cn.ilikes.tools.nosql.jpa.query.sql.element.Properties;
import cn.ilikes.tools.nosql.jpa.query.sql.element.SQLTable;

public class JPASQLQuery extends JPAQuery {

	private IIndexQueryCreateFactory indexQueryCreateFactory;

	public JPASQLQuery(AbClient client, AbstractContext context, String sql) {
		super(client, context, sql);
		IIndexQueryCreateFactory indexQueryCreateFactory = new IndexQueryCreateFactory(context.getPersistenUnitEnv());
		setIndexQueryCreateFactory(indexQueryCreateFactory);

	}

	//	public JPASQLQuery(String sql) {
	//		super(null, null, sql);
	//
	//	}

	private void setIndexQueryCreateFactory(IIndexQueryCreateFactory indexQueryCreateFactory) {
		this.indexQueryCreateFactory = indexQueryCreateFactory;
	}

	private Logger logger = Loggerfactory.instance(JPASQLQuery.class);

	public String printWhere() {
		SQLTable kuTresultable = getjPATable();
		return kuTresultable.toWhere();

	}

	/**
	 * class:ccc and ()
	 * 
	 * @return
	 */
	public String createLunceQuery(SQLTable kuTable, EntityMetaData entityMetaData) {
		String indexQuery = indexQueryCreateFactory.createLunceQuerys(kuTable, entityMetaData);
		indexQuery = assignLunceVariable(indexQuery, parameters);
		return indexQuery;
	}

	private String assignLunceVariable(String indexQuery, Map<Parameter<?>, Object> parameters) {
		String indexQuery_ = indexQuery;
		for (Entry<Parameter<?>, Object> parameter : parameters.entrySet()) {
			String key = parameter.getKey().getName();
			indexQuery_ = indexQuery_.replace(":" + key, parameter.getValue().toString());
		}
		if (Loggerfactory.isdebug(logger))
			Loggerfactory.debug(logger, "create  lunce query     indexQuery => " + indexQuery_ + "   s  " + parameters.size());
		return indexQuery_;
	}

	public String createLunceQuery() {
		SQLTable kuTable = getjPATable();
		AbstractContext context = getContext();
		EntityMetaData entityMetaData = context.getPersistenUnitEnv().getMetaDataManagerFactory().selectIEntityMetaDataByEntityName(kuTable.getTableName());
		String indexQuery = createLunceQuery(kuTable, entityMetaData);
		return indexQuery;
	}

	@Override
	public Object queryResult() {
		QueryType queryType = getQueryType();
		SQLTable kuTable = getjPATable();
		AbstractContext context = getContext();
		EntityMetaData entityMetaData = context.getPersistenUnitEnv().getMetaDataManagerFactory().selectIEntityMetaDataByEntityName(kuTable.getTableName());
		if (entityMetaData == null)
			throw new JPASQLQueryRunTimeException("not find entity name :  " + kuTable.getTableName() + " ; sql :  " + sql);

		String indexQuery = createLunceQuery(kuTable, entityMetaData);
		ABClientIndex clientIndex = getClient().getClientIndex();

		switch (sqlQueryType) {
		case Pages:
			return pagesSearch(indexQuery, entityMetaData, getQueryProperties(), clientIndex);

		case General:
			return generalSearch(queryType, entityMetaData, indexQuery, clientIndex);

		default:
			throw new JPASQLQueryRunTimeException("not find  sqlQueryType " + sqlQueryType + " query type ! ");
		}

	}

	private Object pagesSearch(String indexQuery, EntityMetaData entityMetaData, java.util.Properties properties, ABClientIndex clientIndex) {
		if (Loggerfactory.isdebug(logger))
			Loggerfactory.debug(logger, "create  lunce query     pages  Search => " + indexQuery);
		try {
			PageEntitys pageEntitys = clientIndex.searchPage(indexQuery, entityMetaData, properties, maxResults);
			AbClient abClient = (AbClient) getClient();
			DataHander dataHander = abClient.getDataHander();
			Result[] results = dataHander.seach(entityMetaData, pageEntitys.getEntitys());
			List<Object> resultsList = new ArrayList<Object>();
			for (Result result : results) {
				Node node = abClient.ResultToObject(entityMetaData, result);
				resultsList.add(node.getEntity());
			}
			pageEntitys.setEntitys(resultsList);
			return pageEntitys;
		} catch (ClientIndexingException e) {
			throw new JPASQLQueryRunTimeException(e);
		} catch (JPASQLDataHnaderException e) {
			throw new JPASQLQueryRunTimeException(e);
		} catch (JPASQLClientsException e) {
			throw new JPASQLQueryRunTimeException(e);
		}
	}

	private Object generalSearch(QueryType queryType, EntityMetaData entityMetaData, String indexQuery, ABClientIndex clientIndex) {
		try {
			List<?> keyIds = clientIndex.search(indexQuery, entityMetaData, firstResult, maxResults);
			if (queryType.equals(QueryType.Single)) {
				if (keyIds != null && keyIds.size() > 1)
					throw new JPASQLQueryRunTimeException(" find entity result  size  > 1 ;  result  size : " + keyIds.size());
			}
			AbClient abClient = (AbClient) getClient();
			DataHander dataHander = abClient.getDataHander();
			Result[] results = dataHander.seach(entityMetaData, keyIds);
			if (queryType.equals(QueryType.Single)) {
				Result result = results[0];
				Node node = abClient.ResultToObject(entityMetaData, result);
				return node.getEntity();
			} else {

				List<Object> resultsList = new ArrayList<Object>();
				for (Result result : results) {
					Node node = abClient.ResultToObject(entityMetaData, result);
					resultsList.add(node.getEntity());
				}
				return resultsList;
			}

		} catch (Exception e) {
			throw new JPASQLQueryRunTimeException(e);
		}
	}

}
